#pragma once
#include <stdint.h>
#ifndef UNITTEST
    #include <option/has_loadcell.h>
#else
    // @@TODO find a better way of separating load cell and MMU for unit tests
    // Beware - unit tests have been developed for Try-Load, therefore we pretend LoadCell is not present
    #define HAS_LOADCELL() 0
#endif

#if HAS_LOADCELL()
// we may want to return to try-load sequences on MK4 if E-motor stall turns out to be unreliable
// #define USE_TRY_LOAD
#else
    #define USE_TRY_LOAD
#endif

#define DEFAULT_SAFETYTIMER_TIME_MINS 30

///////////////////////////////////////////

// MMU Error pause position
#define MMU_ERR_X_PAUSE_POS  125
#define MMU_ERR_Y_PAUSE_POS  0
#define MMU_ERR_Z_PAUSE_LIFT 20

// As discussed with our PrusaSlicer profile specialist
// - ToolChange shall not try to push filament into the very tip of the nozzle
// to have some space for additional G-code to tune the extruded filament length
// in the profile
// Beware - this value is used to initialize the MMU logic layer - it will be sent to the MMU upon line up (written into its 8bit register 0x0b)
// However - in the G-code we can get a request to set the extra load distance at runtime to something else (M708 A0xb Xsomething).
// The printer intercepts such a call and sets its extra load distance to match the new value as well.
// The same applies to Pulley slow feed rate (register 0x14)
static constexpr uint8_t MMU2_TOOL_CHANGE_LOAD_LENGTH = 5; // mm
static constexpr float MMU2_LOAD_TO_NOZZLE_FEED_RATE = 20.0F; // mm/s

static constexpr float MMU2_UNLOAD_TO_FINDA_FEED_RATE = 120.0F; // mm/s

// The first the MMU does is initialise its axis. Meanwhile the E-motor will unload 20mm of filament in approx. 1 second.
static constexpr float MMU2_RETRY_UNLOAD_TO_FINDA_LENGTH = 20.0f; // mm
static constexpr float MMU2_RETRY_UNLOAD_TO_FINDA_FEED_RATE = 20.0f; // mm/s

static constexpr float MMU2_RETRY_UNLOAD_FINISH_LENGTH = -40.0f; // mm
static constexpr float MMU2_RETRY_UNLOAD_FINISH_FEED_RATE = 20.0f; // mm/s

static constexpr float MMU2_EXTRUDER_NOZZLE_LENGTH = 20.F;
#ifdef USE_TRY_LOAD
    #ifndef UNITTEST
        #if not PRINTER_IS_PRUSA_MK3_5()
            #error "Beware - this part has been tuned for MK35 (copied from MK3S), it probably won't work for MK4 anymore"
        #endif
    #endif
static constexpr float MMU2_FILAMENT_SENSOR_POSITION = 0; // mm
static constexpr float MMU2_EXTRUDER_PTFE_LENGTH = 42.3f; // mm
static constexpr float MMU2_EXTRUDER_HEATBREAK_LENGTH = 17.7f; // mm
static constexpr float MMU2_VERIFY_LOAD_TO_NOZZLE_TWEAK = -15.F; // mm used to shorten/lenghten (negative number -> shorten) the distange of verify load to nozzle
static constexpr float MMU2_CHECK_FILAMENT_PRESENCE_EXTRUSION_LENGTH = MMU2_EXTRUDER_PTFE_LENGTH + MMU2_EXTRUDER_HEATBREAK_LENGTH + MMU2_VERIFY_LOAD_TO_NOZZLE_TWEAK + MMU2_FILAMENT_SENSOR_POSITION;

static constexpr float MMU2_VERIFY_LOAD_TO_NOZZLE_FEED_RATE = 50.F;

    #define MMU2_LOAD_TO_NOZZLE_SEQUENCE                                       \
        {                                                                      \
            { MMU2_EXTRUDER_HEATBREAK_LENGTH, MMU2_LOAD_TO_NOZZLE_FEED_RATE }, \
            { MMU2_EXTRUDER_NOZZLE_LENGTH + 40, 5.F }                          \
        }
#else
static constexpr float MMU2_EXTRUDER_HEATBREAK_LENGTH = 67.F;
// ram the filament as deep as possible while checking for any obstacles
static constexpr float MMU2_FEED_DISTANCE = 50.F; // 50mm

// Obviously, we want to go as fast as possible, but...
// Beware - the speed has been carefully picked from a broad range to make sure it always detects something.
// The main issue is the fact, that the loadcell's sampling rate is close to the frequency of force spikes generated by the skipping motor.
// To overcome this, a few tricks have been applied:
// - lower detection threshold - may also allow the loadcell to "see" when the filament hits the main plate plastic part (when the forces are much lower)
// - pick a specific speed which is a bit different than the sampling rate
static constexpr float MMU2_FEED_RATE = 31.F; // 31mm/s

    #define MMU2_LOAD_TO_NOZZLE_SEQUENCE                                             \
        {                                                                            \
            { MMU2_EXTRUDER_HEATBREAK_LENGTH - MMU2_FEED_DISTANCE, MMU2_FEED_RATE }, \
            { MMU2_EXTRUDER_NOZZLE_LENGTH + 10, 5.F }                                \
        }
#endif

static constexpr uint8_t MMU2_NO_TOOL = 99;

typedef float feedRate_t;

struct E_Step {
    float extrude; ///< extrude distance in mm
    feedRate_t feedRate; ///< feed rate in mm/s
};

static constexpr E_Step ramming_sequence[] = FILAMENT_MMU2_RAMMING_SEQUENCE;
static constexpr E_Step load_to_nozzle_sequence[] = MMU2_LOAD_TO_NOZZLE_SEQUENCE;
